#include "StdAfx.h"
#include "ShaderCompiler.h"

#include "type.h"
#include "VertexFactory.h"
#include "Shader.h"

#include "D3D9ShaderCompiler.h"

#include "CRC.h"

using namespace RenderSystem;
using namespace Common;

String ShaderProfile::strShaderModel[ShaderProfile::eSM_End] =
{
	"_1_1",
	"_2_0",
	"_3_0",
	"_4_0"
};

String ShaderProfile::strFrequency[ShaderProfile::eF_End] = 
{
	"vs",
	"ps",
	"gs"
};

bool ShaderParameterMap::FindParameterAllocation(const TCHAR* pszParameterName,WORD& rOutBufferIndex,WORD& rOutBaseIndex,WORD& rOutSize,WORD& rOutSamplerIndex) const
{
	IdParamMapConstIterator itrParameter = m_ParameterMap.find(pszParameterName);
	if( itrParameter !=  m_ParameterMap.end() )
	{
		rOutBufferIndex = itrParameter->second.BufferIndex;
		rOutBaseIndex = itrParameter->second.BaseIndex;
		rOutSize = itrParameter->second.Size;
		rOutSamplerIndex = itrParameter->second.SamplerIndex;
		return true;
	}
	else
		return false;
}

void ShaderParameterMap::AddParameterAllocation(const TCHAR* pszParameterName,WORD BufferIndex,WORD BaseIndex,WORD Size,WORD SamplerIndex)
{
	ParameterAllocation allocation;
	allocation.BufferIndex = BufferIndex;
	allocation.BaseIndex = BaseIndex;
	allocation.Size = Size;
	allocation.SamplerIndex = SamplerIndex;

	m_ParameterMap.insert( IdParamMap::value_type( pszParameterName, allocation) );
}

DWORD ShaderParameterMap::GetCRC() const
{
	DWORD ParameterCRC = 0;

	IdParamMapConstIterator itrParamMap = m_ParameterMap.begin();
	for( ; itrParamMap != m_ParameterMap.end(); ++itrParamMap )
	{
		const String& rStrParamName = itrParamMap->first;
		const ParameterAllocation& rParamValue = itrParamMap->second;

		ParameterCRC = MemCrc( rStrParamName.c_str(), rStrParamName.length() * sizeof(TCHAR), ParameterCRC );
		ParameterCRC = MemCrc( &rParamValue, sizeof(rParamValue), ParameterCRC);
	}

	return ParameterCRC;
}

////////////////
ShaderCompiler::ShaderCompiler( void )
{

}

Common::WorkQueue::Response* ShaderCompiler::handleRequest(const Common::WorkQueue::Request* req, const Common::WorkQueue* srcQ)
{
	ShaderCompileJob& rShaderCompileJob = any_cast< ShaderCompileJob& >(req->getData());
	
	rShaderCompileJob.bSucceeded = this->_CompileShader( 
		rShaderCompileJob.szSourceFilename.c_str(),
		rShaderCompileJob.szFunctionName.c_str(),
		rShaderCompileJob.objEnvironment,
		rShaderCompileJob.objShaderProfile,
		rShaderCompileJob.objOutput );
	
	if( !rShaderCompileJob.bSucceeded )
		assert( false );

	rShaderCompileJob.pShaderType->

	return NULL;
}


////////////////////////ShaderCompilerManager////////////////
ShaderCompilerManager::ShaderCompilerManager( )
	:m_rShaderCompiler( D3D9ShaderCompiler() ),m_uCompileChannel(0)
{
	m_CompileWorkQueue.addRequestHandler(m_uCompileChannel, &m_rShaderCompiler);
}

ShaderCompilerManager::~ShaderCompilerManager( void )
{
}

void ShaderCompilerManager::AddCompileJob( const ShaderCompileJob& rCompileJob )
{
	//generate a request
	m_CompileWorkQueue.addRequest( m_uCompileChannel, m_uCompileChannel, Any(rCompileJob) );
}

ShaderCompiler& ShaderCompilerManager::GetShaderCompiler( void ) const
{
	return m_rShaderCompiler;
}

ShaderCompileJobs& ShaderCompilerManager::GetCurrentJob( void )
{
	return m_CurJobs;
}

/** Enqueues a shader compile job with compiler*/
void BeginCompileShader(
	VertexFactoryType* pVFType,
	ShaderType* pShaderType,
	const TCHAR* pszSourceFilename,
	const TCHAR* pszFunctionName,
	const ShaderProfile& rShaderProfile,
	const ShaderCompilerEnvironment& rInEnvironment
	)
{
	ShaderCompilerEnvironment objEnvironment( rInEnvironment );
	// Create a new job and enqueue it with the shader compiling manager
	ShaderCompileJob objNewJob( pVFType, pShaderType, pszSourceFilename, pszFunctionName, rShaderProfile, rInEnvironment);
	
	ShaderCompilerManager::getSingleton().AddCompileJob( objNewJob );
}
